package ru.dcsearch.indexer;

/***************************************************************************
 *   Created by TMC
 *   berechitai@gmail.com
 *
 *   This file is part of DC Indexer project
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 ***************************************************************************/

import java.util.Hashtable;
import java.io.IOException;


public class DownloadScheduler {

    private DCClient mw;
	private Userlist userList;
	
	
	public class UserState {
		
		//State codes
		final static int STATE_DEFAULT = 0;
		final static int STATE_PROCESSING = 1;
		final static int STATE_SUCCESSED = 2;
		final static int STATE_NOSLOTS = 3;
		final static int STATE_TIMEOUT = 4;
		final static int STATE_LOWSPEED = 5;
		final static int STATE_OTHER_EXCEPTION = 6;
		
		private int lastStatus = STATE_DEFAULT;
		private int lastStatusCount = 1;
		private double lastRating = 0;
		
		public UserState(int status) {
			
			lastStatus = status;
		}
		
		public UserState() {
			
			
		}
		
		
		public void setStatus(int status) {
			
			if (status == lastStatus) {
				lastStatusCount++;
			} else {
				
				lastStatusCount = 1;
				lastStatus = status;
			}
		}
		
		public int getLastStatus() {
			
			return lastStatus;
		}
		
		public int getLastStatusCount() {
			
			return lastStatusCount;
		}
		
		public void setLastRating(double rating) {
			
			lastRating = rating;
		}
		
		public double getLastRating() {
			
			return lastRating;
		}
		
	};
	
	private Hashtable<String, UserState> userStates;
	
	public DownloadScheduler(DCClient mw) {

        this.mw = mw;
		this.userList = mw.ul;
		
		userStates = new Hashtable<String, UserState>();
	}
	
	public void downloadWorker() {

        int i = 0;
        String user;
		    while (!(user = getNextUserInSchedule()).equals("")) {

                i++;
                while (!mw.pp.freePortExists()) {
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                    }
                }
                    Logger.printGlobalLog("WORKING WITH USER NUMBER: "+ i + ", NAME: " + user);
                  try {
                    mw.cc.NewCC(user, "", "files.xml.bz2", ClientConnectionManager.Download);
                  } catch (IOException e) {

                       e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                  }


            }
	}
	
	
	public String getNextUserInSchedule() {
		
		int index = 0;
		String foundUser = "";
		double foundRating = 0;
		
		while (true) {
			try {
				String user = userList.getItem(index);
				
				UserState state;
				if (userStates.containsKey(user)) {
					
					state = userStates.get(user);
				
				} else {
					
					state = new UserState();
					userStates.put(user, state);
				}
				
				double rating = calculateUserRating(user, state);
				if (rating > 0) {
					
					if (foundUser.equals("") || rating > foundRating) {
						
						foundRating = rating;
						foundUser = user;
					}
					
				}
				
				
				
				index++;
			
			} catch (ArrayIndexOutOfBoundsException e) {
				break;
			} catch(Exception e) {			
				  index++;
			}
				
		}
		
		if (!foundUser.equals("")) {
				setUserState(foundUser, UserState.STATE_PROCESSING);
		}
		
		 return foundUser;
	}
	
	
	private double calculateUserRating(String user, UserState state) {
		
		double rating = 0;
		
		if (state.getLastStatus() == UserState.STATE_DEFAULT) {
			
			rating = Double.parseDouble(userList.getShare(user));
			
		}
		
		else if (state.getLastStatus() == UserState.STATE_PROCESSING || 
					state.getLastStatus() == UserState.STATE_SUCCESSED) {
			
			rating = 0;
			
		}
		
		else if (state.getLastStatus() == UserState.STATE_TIMEOUT) {
			
			rating = Double.parseDouble(userList.getShare(user)) / (10 * (0.5*(float)state.getLastStatusCount()));
			
		}
		
		else if (state.getLastStatus() == UserState.STATE_NOSLOTS) {
			
			rating = Double.parseDouble(userList.getShare(user)) / (1.5 *(0.5*(float)state.getLastStatusCount()));
			
		}
		
		else if (state.getLastStatus() == UserState.STATE_LOWSPEED) {
			
			rating = Double.parseDouble(userList.getShare(user)) / (2*(1.0*(float)state.getLastStatusCount()));
			
		}
		
		state.setLastRating(rating);
		
		return rating;
	}
	
	public void setUserState(String name, int state) {
		
		if (userStates.containsKey(name)) {
			
			userStates.get(name).setStatus(state);
			
		}
		
	}
	
}
